package com.derbysoft.nuke.configkeeper.service;

import com.derbysoft.nuke.configkeeper.domain.Config;
import com.derbysoft.nuke.configkeeper.domain.ConfigHistory;
import com.derbysoft.nuke.configkeeper.repository.ConfigRepository;
import com.google.inject.Inject;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultConfigService implements ConfigService {

    @Inject
    private ConfigRepository configRepository;

    @Override
    public List<String> getSources() {
        return configRepository.getSources();
    }

    @Override
    public boolean available(String source) {
        Config config = configRepository.get(source);
        return config != null;
    }

    @Override
    public Long getCurrentTimestamp(String source) {
        Config config = configRepository.get(source);
        if (config == null) {
            return 0L;
        }
        return config.getTimestamp();
    }

    @Override
    public Map<String, String> getAll(String source) {
        Config config = configRepository.get(source);
        if (config == null || config.getConfigs() == null) {
            return new HashMap<>();
        }
        Map<String, String> result = new HashMap<>(config.getConfigs());
        result.put("@timestamp", config.getTimestamp().toString());
        return result;
    }

    @Override
    public void setProperty(String source, String key, String value) {
        if (value == null) {
            removeProperty(source, key);
            return;
        }
        long timestamp = System.currentTimeMillis();
        String action;
        Config config = configRepository.get(source);
        if (config == null) {
            action = ConfigHistory.ACTION_ADD;

            Map<String, String> configs = new HashMap<>();
            configs.put(key, value);

            config = Config.builder()
                    .source(source)
                    .timestamp(timestamp)
                    .configs(configs)
                    .build();
        } else {
            Map<String, String> configs = config.getConfigs();
            if (configs.containsKey(key)) {
                action = ConfigHistory.ACTION_UPDATE;
            } else {
                action = ConfigHistory.ACTION_ADD;
            }
            if (value.equals(configs.get(key))) {
                // no need to update
                return;
            }
            configs.put(key, value);
            config.setTimestamp(timestamp);
        }

        ConfigHistory configHistory = ConfigHistory.builder()
                .action(action)
                .source(source)
                .key(key)
                .value(value)
                .timestamp(timestamp)
                .build();
        configRepository.save(config);
        configRepository.saveHistory(configHistory);
    }

    @Override
    public void removeProperty(String source, String key) {
        Config config = configRepository.get(source);
        if (config == null || config.getConfigs() == null || !config.getConfigs().containsKey(key)) {
            return;
        }
        config.getConfigs().remove(key);
        long timestamp = System.currentTimeMillis();
        config.setTimestamp(timestamp);

        ConfigHistory configHistory = ConfigHistory.builder()
                .action(ConfigHistory.ACTION_DELETE)
                .source(source)
                .key(key)
                .timestamp(timestamp)
                .build();
        configRepository.save(config);
        configRepository.saveHistory(configHistory);
    }

    @Override
    public String getProperty(String source, String key) {
        Config config = configRepository.get(source);
        if (config == null) {
            return null;
        }
        return config.getConfigs().get(key);
    }

    @Override
    public List<ConfigHistory> findHistory(String source, Long timestamp) {
        return configRepository.findHistory(source, timestamp);
    }
}
